/*---------------------------------------------------------------------*/
/* --- STC MCU Limited ------------------------------------------------*/
/* --- STC 1T Series MCU Demo Programme -------------------------------*/
/* --- Mobile: (86)13922805190 ----------------------------------------*/
/* --- Fax: 86-0513-55012956,55012947,55012969 ------------------------*/
/* --- Tel: 86-0513-55012928,55012929,55012966 ------------------------*/
/* --- Web: www.STCMCU.com --------------------------------------------*/
/* --- Web: www.STCMCUDATA.com  ---------------------------------------*/
/* --- QQ:  800003751 -------------------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序            */
/*---------------------------------------------------------------------*/

#include "config.h"
#include "GPIO.h"
#include "UART.h"
#include "delay.h"
#include "soft_uart.h"
#include "ADC.h"

#ifndef __SDCC
#include <lint.h>
#error "This header file must be used for SDCC compiler !"
#endif
#include <compiler.h>

/***************	功能说明	****************

本例程基于STC8H8K64U为主控芯片的实验箱8进行编写测试，STC8G、STC8H系列芯片可通用参考.

下载时, 选择时钟 24MHz (可以在配置文件"config.h"中修改).

******************************************/
#define LED_R  P55
#define LED_G  P54
#define LED_B  P32

#define ADC_CH 3

/*************	本地变量声明	**************/

/*************	本地函数声明	**************/

/*************  外部函数和变量声明 *****************/

/******************** IO配置函数 **************************/
void GPIO_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 结构定义
    GPIO_InitStructure.Mode = GPIO_OUT_PP; // 指定IO的输入或输出方式

    GPIO_InitStructure.Pin = GPIO_Pin_2;        // 指定要初始化的IO,
    GPIO_Inilize(GPIO_P3, &GPIO_InitStructure); // 初始化

    GPIO_InitStructure.Pin = GPIO_Pin_4;        // 指定要初始化的IO
    GPIO_Inilize(GPIO_P5, &GPIO_InitStructure); // 初始化

    GPIO_InitStructure.Pin = GPIO_Pin_5;        // 指定要初始化的IO
    GPIO_Inilize(GPIO_P5, &GPIO_InitStructure); // 初始化

    GPIO_InitStructure.Pin = GPIO_Pin_0 | GPIO_Pin_1; // 指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
    GPIO_InitStructure.Mode = GPIO_PullUp;            // GPIO_PullUp;            // 指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(GPIO_P3, &GPIO_InitStructure);       // 初始化

    GPIO_InitStructure.Pin = GPIO_Pin_3;        // 指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
    GPIO_InitStructure.Mode = GPIO_HighZ;       // GPIO_PullUp;            // 指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
    GPIO_Inilize(GPIO_P3, &GPIO_InitStructure); // 初始化
}

void ADC_config(void)
{
    ADC_InitTypeDef ADC_InitStructure; // 结构定义

    ADC_InitStructure.ADC_SMPduty = 31;                    // ADC 模拟信号采样时间控制, 0~31（注意： SMPDUTY 一定不能设置小于 10）
    ADC_InitStructure.ADC_CsSetup = 0;                     // ADC 通道选择时间控制 0(默认),1
    ADC_InitStructure.ADC_CsHold = 1;                      // ADC 通道选择保持时间控制 0,1(默认),2,3
    ADC_InitStructure.ADC_Speed = ADC_SPEED_2X16T;         // 设置 ADC 工作时钟频率	ADC_SPEED_2X1T~ADC_SPEED_2X16T
    ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; // ADC结果调整,	ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED
    ADC_InitStructure.ADC_Interrupt = ENABLE;
    ADC_InitStructure.ADC_Power = ENABLE;
    ADC_InitStructure.ADC_Priority = Priority_0;
    ADC_Inilize(&ADC_InitStructure); // 初始化
    ADC_PowerControl(ENABLE);        // ADC电源开关, ENABLE或DISABLE
}

void printf_vol(u16 vol)
{
    TxSend(vol / 1000 + 48);
    TxSend(vol % 1000 / 100 + 48);
    TxSend(vol % 100 / 10 + 48);
    TxSend(vol % 10 + 48);
    TxSend('\r');
    TxSend('\n');
}

void led_ctrl(u16 vol)
{
    if (vol < 190) {
        LED_R = 1;
        LED_G = 0;
        LED_B = 0;
    } else if ((vol > 200) && (vol < 390)) {
        LED_R = 1;
        LED_G = 1;
        LED_B = 0;
    } else if ((vol > 400) && (vol < 590)) {
        LED_R = 1;
        LED_G = 1;
        LED_B = 1;
    } else if ((vol > 600) && (vol < 790)) {
        LED_R = 1;
        LED_G = 1;
        LED_B = 0;
    } else if (vol > 800) {
        LED_R = 1;
        LED_G = 0;
        LED_B = 0;
    }
}

#define FILTER_SIZE 15      // 滤波窗口大小
int adcBuffer[FILTER_SIZE]; // 存储最近的几个采样值
int bufferIndex = 0;        // 当前索引位置
int sum = 0;                // 数组元素总和

void initFilter()
{
    for (int i = 0; i < FILTER_SIZE; i++) {
        adcBuffer[i] = Get_ADCResult(ADC_CH);
        sum += adcBuffer[i];
    }
}

int getFilteredADCResult(int channel)
{
    int newVol = Get_ADCResult(channel);

    // 更新总和：减去旧值，加上新值
    sum -= adcBuffer[bufferIndex];
    sum += newVol;
    adcBuffer[bufferIndex] = newVol;

    // 移动索引位置
    bufferIndex++;
    if (bufferIndex >= FILTER_SIZE) {
        bufferIndex = 0;
    }

    // 返回平均值
    return sum / FILTER_SIZE;
}

// 增加低通滤波相关的变量
float lowPassAlpha = 0.05; // 滤波系数，可以根据需要调整
u16 filteredVolPrev = 0;   // 上一次滤波后的电压值

int user_abs(int x)
{
    return (x >= 0) ? x : -x;
}

/******************** 主函数 *************F*************/
void main(void)
{
    u16 vol;
    u16 lastVol = 0xFFFF;
    u16 filteredVol = 0;
    int vol_diff = 0;

    GPIO_config();
    ADC_config();

    ES = 1;
    EA = 1;

    initFilter(); // 初始化滤波器

    vol = getFilteredADCResult(ADC_CH);
    led_ctrl(vol);

    while (1) {
        delay_ms(5);

        vol = getFilteredADCResult(ADC_CH);
        printf_vol(vol);

        // 应用低通滤波
        filteredVol = lowPassAlpha * vol + (1 - lowPassAlpha) * filteredVolPrev;
        filteredVolPrev = filteredVol;

        vol_diff = (int)(filteredVol - lastVol);
        if (user_abs(vol_diff) < 5) continue;

        lastVol = filteredVol;
        led_ctrl(lastVol);
    }
}